02. Constructor Functions

L3 8 HS - Constructor Functions

Previously, we have created objects using the object literal notation. Likewise, we can even write functions that return objects. There is yet another way for us to create objects, and it is the foundation of object-oriented JavaScript: the constructor function. We saw a bit of it back in Lesson 1 when invoking the Object() constructor function. Now, let's take a deeper dive into it!

To instantiate (i.e., create) a new object, we use the new operator to invoke the function:

new SoftwareDeveloper();

The first thing to note above is the use of the new keyword. Second, note that the name of the constructor function, SoftwareDeveloper(), is written with the first letter capitalized to visually distinguish it from a regular function.

Keep in mind that even though the function's name starts with a capital, that doesn't automatically make this a constructor function (i.e., though developers name constructor functions in CamelCase by convention, it is not enforced by the language). What does make SoftwareDeveloper() a constructor function are:

  • The use of the new operator to invoke the function
  • How the function is coded internally (which we'll look at right now!)

Constructor Functions: Structure and Syntax

This is what the internals of a constructor function looks like:

function SoftwareDeveloper() {
  this.favoriteLanguage = 'JavaScript';
}

This might seem a bit different than the functions you've written up to this point, so let's break it down!

First, rather than declaring local variables, constructor functions persist data with the this keyword. The above function will add a favoriteLanguage property to any object that it creates, and assigns it a default value of 'JavaScript'. Don't worry too much about this in a constructor function for now; just know that this refers to the new object that was created by using the new keyword in front of the constructor function. We'll go into more detail about this soon!

One last thing that might seem unusual is that this function doesn't seem to return anything! Constructor functions in JavaScript should not have an explicit return value (i.e., there should not be return statement).

Great! Now that we've seen the structure and syntax of a constructor, how can we use it to create an object?

Creating a New Object

As we've seen above, let's use the new operator to create a new object:

let developer = new SoftwareDeveloper();

We've saved the return value of this invocation to the variable developer. Let's execute console.log(developer); to log this SoftwareDeveloper object to the console:

_The `SoftwareDeveloper` object is logged to the console._

The SoftwareDeveloper object is logged to the console.

L3 -11 - Comparing Objects V1

Creating Multiple Objects

What's more: we can even use the same constructor function to create as many objects as we'd like!

Let's invoke the same SoftwareDeveloper() constructor two more times to instantiate two additional objects: engineer and programmer.

let engineer = new SoftwareDeveloper();
let programmer = new SoftwareDeveloper();

console.log(engineer);
// SoftwareDeveloper { favoriteLanguage: 'JavaScript' }

console.log(programmer);
// SoftwareDeveloper { favoriteLanguage: 'JavaScript' }

Constructor Functions Can Have Parameters

Just like regular functions, one benefit of using constructor functions is that they can also accept arguments. Let's update the constructor above to accept a single argument, and assign the name property to it:

function SoftwareDeveloper(name) {
  this.favoriteLanguage = 'JavaScript';
  this.name = name;
}

In the updated SoftwareDeveloper() function, whatever value is passed into the function will be the value of the object's name property. Let's check it out:

let instructor = new SoftwareDeveloper('Andrew');

console.log(instructor);
// SoftwareDeveloper { favoriteLanguage: 'JavaScript', name: 'Andrew' }

Great! And as we've seen above, we can create different objects using the same constructor. Let's call the same constructor function but pass a different argument this time:

let teacher = new SoftwareDeveloper('Richard');

console.log(teacher);
// SoftwareDeveloper { favoriteLanguage: 'JavaScript', name: 'Richard' }

Just to recap: above, we passed the string 'Richard' into the SoftwareDeveloper() constructor function, then instantiated a new object. 'Richard' then became the value of the name property in the teacher object.

Let's check out another example!

L3 - 14 - Instantiating An Object

Which of the following about constructor functions are true? Constructor functions (select all that apply)…

SOLUTION:
  • must be invoked with `new`
  • are used to instantiate a new object

What happens if a constructor function begins with a lower-case letter?

SOLUTION: Nothing. It will still work.

Start Quiz:

/*

Now it's your turn to create a constructor function. Declare a
`Sandwich` constructor function that takes three parameters:

1. `bread` (string) - the type of bread for the sandwich (e.g. "Wheat")
2. `meat` (array) - the meats to put on the sandwich
   (e.g. `[]` for a vegetarian sandwich!)
3. `vegetables` (array) - the vegetables to include in the sandwich

*/

⚠️ Omitting the new Operator ⚠️

What happens if you inadvertently invoke a constructor function without using the new operator?

function SoftwareDeveloper(name) {
   this.favoriteLanguage = 'JavaScript';
   this.name = name;
}

let coder = SoftwareDeveloper('David');

console.log(coder);
// undefined

What's going on? Without using the new operator, no object was created. The function was invoked just like any other regular function. Since the function doesn't return anything (except undefined, which all functions return by default), the coder variable ended up being assigned to undefined.

One more thing to note: since this function was invoked as a regular function, the value of this is also drastically different. Don't worry too much about this for now; we'll take a deep dive into the this keyword in the very next section!

Seeing the Object's Constructor (instanceof)

What if we want to see if an object was created with a constructor function in the first place? We can use the instanceof (which returns a boolean) to give us some insight. Let's check it out!

L3 - 21 - How To View Constructor Functions

💡 instanceof and the Prototype Chain 💡

In the above example, instanceof confirmed that a specific constructor function did in fact create a specific object. We know this because we directly instantiated the dev object after invoking the Developer() constructor function.

Many times, however, it's a bit more complex: the instanceof operator actually tests whether or not that constructor appears in the prototype chain of an object. This means that we can't always check exactly which constructor created that object, but it does give us insight as to what other properties and methods an object may have access to.

For now, don't worry too much about the prototype chain or any of these additional properties or methods; we'll take a very close look at them soon!

Consider the following constructors:

function Finch(name) {
  this.kingdom = 'Animalia';
  this.name = name;
}

function Sparrow(name) {
  this.kingdom = 'Animalia';
  this.name = name;
}

Let's create an instance of each constructor:

const atticus = new Finch('Atticus');
const jack = new Sparrow('Jack');

What is the result when atticus instanceof Sparrow; is executed?

SOLUTION: `false`

Summary

JavaScript's class system is built directly on using functions and objects. Calling (i.e., invoking) a constructor function with the new operator instantiates a new object. The same constructor function can be used to create different objects.

We've discussed functions, objects, and this throughout this course. As it turns out, all three are very much interconnected with one another! We'll examine their relationship in the next section as we take an in-depth look at the this keyword.

Further Research